#include "drawer.h"
#include <boost/assert.hpp>
void drawer::add(Graph& G)
{
  Graph::edge_iterator ei,ei_end;
  for (tie(ei, ei_end) = edges(G); ei != ei_end; ++ei) {

    put(edge_weight, G, *ei, 0.00001);
  }

  /// Circle layout need for spring layout due to same vertices positions
  circle_graph_layout(G,get(vertex_position, G),20.0);
    
  //      if(kamada_kawai_spring_layout(G,get(vertex_position, G),get(edge_weight, G),square_topology<>(),boost::side_length<double>(10),boost::layout_tolerance<>(), 1))cout<<"KAMADA_KAWAI\n";
  //else  /// If spring layout impossible, try direct layout
  {
    fruchterman_reingold_force_directed_layout
      (G,get(vertex_position, G),square_topology<>(20.0));
    cout<<"fruchterman_reingold_force_directed_layout"<<endl;
  }
    
  //  BOOST_CHECK(ok);

  //random_graph_layout
  //circle_graph_layout
  //fruchterman_reingold_force_directed_layout
  // (G,get(vertex_position, G),square_topology<>(20.0));
  //using FD::page; 
  //    FD::page* pg = new FD::page;
  page_vector.push_back(new FD::page);
    
  //FD::page p1;
  FD::FeynDiagram *fd = new FD::FeynDiagram(*page_vector.back());
  //FD::FeynDiagram fd(p1);

  std::map<Graph::vertex_descriptor,FD::vertex_dot*> vmap;
  Graph::vertex_iterator vi,vi_end;
  for (tie(vi, vi_end) = vertices(G); vi != vi_end; ++vi) {

    cout<<"YYYYYYYYYYYYYY x,y=("<<get(vertex_position, G)[*vi][0]<<", "<<get(vertex_position, G)[*vi][1]<<endl;
    FD::vertex_dot* v1 = new FD::vertex_dot(*fd,get(vertex_position, G)[*vi][0],get(vertex_position, G)[*vi][1]);
    vmap[*vi] = v1;
  }
  // Mark all edges as unvisited
  for (tie(ei, ei_end) = edges(G); ei != ei_end; ++ei) G[*ei].visited = false;
  // Find and draw parallel edges
  Graph::out_edge_iterator pari,pari_end;
  // Visit all edges and find parallel
  for (tie(ei, ei_end) = edges(G); ei != ei_end; ++ei) 
    {
      //      std::make_pair(pari,pari_end) = edge_range(source(*ei,G),target(*ei,G),G);
      if(!G[*ei].visited)
        {
          std::vector<Graph::edge_descriptor> par_edge_set;
          for(tie(pari,pari_end)=out_edges(source(*ei,G),G);pari != pari_end;++pari)
            if((out_edges(target(*ei,G),G).second != 
                std::find(
                          out_edges(target(*ei,G),G).first, // firs element
                          out_edges(target(*ei,G),G).second,//last element 
                          *pari)))// && (!G[*pari].visited))
              {
                par_edge_set.push_back(*pari);
                G[*pari].visited = true;
              }
          cout<<"PARA_NUM = "<<par_edge_set.size()<<endl;
          switch(par_edge_set.size())
            {
            case 1:   // single edge
              {
                stringstream p_prop1;
                p_prop1<<latex<<G[par_edge_set[0]].gmomentum;
                cout<<G[par_edge_set[0]].gmomentum<<"    "<<p_prop1.str()<<endl;
                std::string* p_ref = new std::string(p_prop1.str());
                if(G[par_edge_set[0]].type == 1)
                  {
                    FD::line_plain* f1 = new FD::line_plain(*fd,*vmap[source(par_edge_set[0],G)],*vmap[target(par_edge_set[0],G)]);
                    FD::xy refpt, tanvect;
                    refpt = f1->curve->f(0.5);
                    tanvect = f1->curve->tang(0.5);
                    cout<<tanvect.angle()<<endl;
                    if((tanvect.angle() >= -90)&&(tanvect.angle() < 90))
                      {
                        refpt += 0.5 * tanvect.perp();
                        FD::text* txt  = new  FD::text(*fd,const_cast<char*>(p_ref->c_str()),refpt,0.5,0,tanvect.angle());
                        txt->fontsize.scale(0.7);

                      }
                    else
                      {
                        refpt -= 0.8 * tanvect.perp();
                        FD::text* txt  = new  FD::text(*fd,const_cast<char*>(p_ref->c_str()),refpt,0.5,0,180+tanvect.angle());
                        txt->fontsize.scale(0.7);
                      }
                      
                  }
                else if(G[par_edge_set[0]].type == 0)
                  { 
                    FD::line_wiggle* f1 = new FD::line_wiggle(*fd,*vmap[source(par_edge_set[0],G)],*vmap[target(par_edge_set[0],G)]);
                    f1->arrowon.settrue();
                    FD::xy refpt, tanvect;
                    refpt = f1->curve->f(0.5);
                    tanvect = f1->curve->tang(0.5);
                    refpt += 0.5 * tanvect.perp();
                    if((tanvect.angle() >= -90)&&(tanvect.angle() < 90))
                      {
                        refpt += 0.5 * tanvect.perp();
                        FD::text* txt  = new  FD::text(*fd,const_cast<char*>(p_ref->c_str()),refpt,0.5,0,tanvect.angle());
                        txt->fontsize.scale(0.7);
                      }
                    else
                      {
                        refpt -= 0.8 * tanvect.perp();
                        FD::text* txt  = new  FD::text(*fd,const_cast<char*>(p_ref->c_str()),refpt,0.5,0,180+tanvect.angle());
                        txt->fontsize.scale(0.7);
                      }

                  }
                else if(G[par_edge_set[0]].type == -1)
                  { 
                    FD::line_plain* f1 = new FD::line_plain(*fd,*vmap[source(par_edge_set[0],G)],*vmap[target(par_edge_set[0],G)]); f1->dashon.settrue();
                    FD::xy refpt, tanvect;
                    refpt = f1->curve->f(0.5);
                    tanvect = f1->curve->tang(0.5);
                    refpt += 0.5 * tanvect.perp();
                    if((tanvect.angle() >= -90)&&(tanvect.angle() < 90))
                      {
                        refpt += 0.5 * tanvect.perp();
                        FD::text* txt  = new  FD::text(*fd,const_cast<char*>(p_ref->c_str()),refpt,0.5,0,tanvect.angle());
                        txt->fontsize.scale(0.7);
                      }
                    else
                      {
                        refpt -= 0.8 * tanvect.perp();
                        FD::text* txt  = new  FD::text(*fd,const_cast<char*>(p_ref->c_str()),refpt,0.5,0,180+tanvect.angle());
                        txt->fontsize.scale(0.7);
                      }
                  }
                else cout<<"err detected"<<endl;
              }
              break;
            case 2:   // two parallel edges
              {
                stringstream p_prop1,p_prop2;
                p_prop1<<latex<<G[par_edge_set[0]].gmomentum;
                p_prop2<<latex<<G[par_edge_set[1]].gmomentum;
                // new way of const_cast=)
                std::string* p_ref1 = new std::string(p_prop1.str());
                std::string* p_ref2 = new std::string(p_prop2.str());
                FD::xy midpt, arcpt1, arcpt2;
                // same direction edges 
                if((source(par_edge_set[0],G) == source(par_edge_set[1],G))&&
                   (target(par_edge_set[0],G) == target(par_edge_set[1],G)))
                  {
                    midpt = 0.5 * (*vmap[source(par_edge_set[0],G)] + *vmap[target(par_edge_set[0],G)]);
                    arcpt1 = midpt + 2.0 * (*vmap[source(par_edge_set[0],G)] - *vmap[target(par_edge_set[0],G)]).perp();
                    arcpt2 = midpt - 2.0 * (*vmap[source(par_edge_set[0],G)] - *vmap[target(par_edge_set[0],G)]).perp();
                  }
                //oposite direction edges
                else if((source(par_edge_set[0],G) == target(par_edge_set[1],G))&&(target(par_edge_set[0],G) == source(par_edge_set[1],G)))
                  {
                    midpt = 0.5 * (*vmap[source(par_edge_set[0],G)] + *vmap[target(par_edge_set[0],G)]);
                    arcpt1 = midpt + 2.0 * (*vmap[source(par_edge_set[0],G)] - *vmap[target(par_edge_set[0],G)]).perp();
                    arcpt2 = midpt + 2.0 * (*vmap[source(par_edge_set[1],G)] - *vmap[target(par_edge_set[1],G)]).perp();
                  }
                // drawing edge 0 
                if(G[par_edge_set[0]].type == 1){ FD::line_plain* f1 = new FD::line_plain(*fd,*vmap[source(par_edge_set[0],G)],*vmap[target(par_edge_set[0],G)]);
                  f1->arcthru(arcpt1);
                  FD::xy refpt, tanvect;
                  refpt = f1->curve->f(0.5);
                  tanvect = f1->curve->tang(0.5);
                  refpt += 0.5 * tanvect.perp();
                  if((tanvect.angle() >= -90)&&(tanvect.angle() < 90))
                    {
                      refpt += 0.5 * tanvect.perp();
                      FD::text* txt  = new  FD::text(*fd,const_cast<char*>(p_ref1->c_str()),refpt,0.5,0,tanvect.angle());
                      txt->fontsize.scale(0.7);
                    }
                  else
                    {
                      refpt -= 0.8 * tanvect.perp();
                      FD::text* txt  = new  FD::text(*fd,const_cast<char*>(p_ref1->c_str()),refpt,0.5,0,180+tanvect.angle());
                      txt->fontsize.scale(0.7);
                    }
                }
                else if(G[par_edge_set[0]].type == 0){
                  FD::line_wiggle* f1 = new FD::line_wiggle(*fd,*vmap[source(par_edge_set[0],G)],*vmap[target(par_edge_set[0],G)]);
                  f1->arcthru(arcpt1);
                  FD::xy refpt, tanvect;
                  refpt = f1->curve->f(0.5);
                  tanvect = f1->curve->tang(0.5);
                  refpt += 0.5 * tanvect.perp();
                  if((tanvect.angle() >= -90)&&(tanvect.angle() < 90))
                    {
                      refpt += 0.5 * tanvect.perp();
                      FD::text* txt  = new  FD::text(*fd,const_cast<char*>(p_ref1->c_str()),refpt,0.5,0,tanvect.angle());
                      txt->fontsize.scale(0.7);
                    }
                  else
                    {
                      refpt -= 0.8 * tanvect.perp();
                      FD::text* txt  = new  FD::text(*fd,const_cast<char*>(p_ref1->c_str()),refpt,0.5,0,180+tanvect.angle());
                      txt->fontsize.scale(0.7);
                    }
                }
                else if(G[par_edge_set[0]].type == -1)
                  { FD::line_plain* f1 = new FD::line_plain(*fd,*vmap[source(par_edge_set[0],G)],*vmap[target(par_edge_set[0],G)]); f1->dashon.settrue();
                    f1->arcthru(arcpt1);
                    FD::xy refpt, tanvect;
                    refpt = f1->curve->f(0.5);
                    tanvect = f1->curve->tang(0.5);
                    refpt += 0.5 * tanvect.perp();
                    if((tanvect.angle() >= -90)&&(tanvect.angle() < 90))
                      {
                        refpt += 0.5 * tanvect.perp();
                        FD::text* txt  = new  FD::text(*fd,const_cast<char*>(p_ref1->c_str()),refpt,0.5,0,tanvect.angle());
                        txt->fontsize.scale(0.7);
                      }
                    else
                      {
                        refpt -= 0.8 * tanvect.perp();
                        FD::text* txt  = new  FD::text(*fd,const_cast<char*>(p_ref1->c_str()),refpt,0.5,0,180+tanvect.angle());
                        txt->fontsize.scale(0.7);
                      }
                  }
                else cout<<"err detected"<<endl;
                  
                // drawing edge 1
                if(G[par_edge_set[1]].type == 1){ FD::line_plain* f1 = new FD::line_plain(*fd,*vmap[source(par_edge_set[1],G)],*vmap[target(par_edge_set[1],G)]);
                  f1->arcthru(arcpt2);
                  FD::xy refpt, tanvect;
                  refpt = f1->curve->f(0.5);
                  tanvect = f1->curve->tang(0.5);
                  refpt += 0.5 * tanvect.perp();
                  if((tanvect.angle() >= -90)&&(tanvect.angle() < 90))
                    {
                      refpt += 0.5 * tanvect.perp();
                      FD::text* txt  = new  FD::text(*fd,const_cast<char*>(p_ref2->c_str()),refpt,0.5,0,tanvect.angle());
                      txt->fontsize.scale(0.7);
                    }
                  else
                    {
                      refpt -= 0.8 * tanvect.perp();
                      FD::text* txt  = new  FD::text(*fd,const_cast<char*>(p_ref2->c_str()),refpt,0.5,0,180+tanvect.angle());
                      txt->fontsize.scale(0.7);
                    }
                }
                else if(G[par_edge_set[1]].type == 0){
                  FD::line_wiggle* f1 = new FD::line_wiggle(*fd,*vmap[source(par_edge_set[1],G)],*vmap[target(par_edge_set[1],G)]);
                  f1->arcthru(arcpt2);
                  FD::xy refpt, tanvect;
                  refpt = f1->curve->f(0.5);
                  tanvect = f1->curve->tang(0.5);
                  refpt += 0.5 * tanvect.perp();
                  if((tanvect.angle() >= -90)&&(tanvect.angle() < 90))
                    {
                      refpt += 0.5 * tanvect.perp();
                      FD::text* txt  = new  FD::text(*fd,const_cast<char*>(p_ref2->c_str()),refpt,0.5,0,tanvect.angle());
                      txt->fontsize.scale(0.7);
                    }
                  else
                    {
                      refpt -= 0.8 * tanvect.perp();
                      FD::text* txt  = new  FD::text(*fd,const_cast<char*>(p_ref2->c_str()),refpt,0.5,0,180+tanvect.angle());
                      txt->fontsize.scale(0.7);
                    }
                }
                else if(G[par_edge_set[1]].type == -1)
                  { FD::line_plain* f1 = new FD::line_plain(*fd,*vmap[source(par_edge_set[1],G)],*vmap[target(par_edge_set[1],G)]); f1->dashon.settrue();
                    f1->arcthru(arcpt2);
                    FD::xy refpt, tanvect;
                    refpt = f1->curve->f(0.5);
                    tanvect = f1->curve->tang(0.5);
                    refpt += 0.5 * tanvect.perp();
                    if((tanvect.angle() >= -90)&&(tanvect.angle() < 90))
                      {
                        refpt += 0.5 * tanvect.perp();
                        FD::text* txt  = new  FD::text(*fd,const_cast<char*>(p_ref2->c_str()),refpt,0.5,0,tanvect.angle());
                        txt->fontsize.scale(0.7);
                      }
                    else
                      {
                        refpt -= 0.8 * tanvect.perp();
                        FD::text* txt  = new  FD::text(*fd,const_cast<char*>(p_ref2->c_str()),refpt,0.5,0,180+tanvect.angle());
                        txt->fontsize.scale(0.7);
                      }
                  }
                else cout<<"err detected"<<endl;
                break;
              }
            case 3:   // 3 parallel edges possible only in bubblesor  in 4part vertex theory
              {
                cout<<3<<endl;  
                break;
              }
            }
        }
    }
  /*
    for (tie(ei, ei_end) = edges(G); ei != ei_end; ++ei) 
    {
    if(G[*ei].type == 1) FD::line_plain* f1 = new FD::line_plain(*fd,*vmap[source(*ei,G)],*vmap[target(*ei,G)]);
    else if(G[*ei].type == 0)
    {
    FD::line_wiggle* f1 = new FD::line_wiggle(*fd,*vmap[source(*ei,G)],*vmap[target(*ei,G)]);
    FD::xy midpt, arcpt;
    midpt = 0.5 * (*vmap[source(*ei,G)] + *vmap[target(*ei,G)]);
    arcpt = midpt + 4.0 * (*vmap[source(*ei,G)] - *vmap[target(*ei,G)]).perp();
    Graph::edge_descriptor edis;
    //bool hp = has_par_edges(edis((*ei)),G);
    bool hp = false;
    if(hp) f1->arcthru(arcpt);
    }
    else if(G[*ei].type == -1)
    { FD::line_plain* f1 = new FD::line_plain(*fd,*vmap[source(*ei,G)],*vmap[target(*ei,G)]);
    f1->dashon.settrue();

    FD::xy midpt, arcpt;
    midpt = 0.5 * (*vmap[source(*ei,G)] + *vmap[target(*ei,G)]);
    arcpt = midpt + 4.0 * (*vmap[source(*ei,G)] - *vmap[target(*ei,G)]).perp();
            
    f1->arcthru(arcpt);
    }
    else cout<<"err detected"<<endl;
    }*/
}

/// output diagrams when drawer  destructed
drawer::~drawer() 
{
  ofstream off("dia.ps");
  cout<<"SIZE: "<<page_vector.size()<<endl;
  page_vector.back()->output(off);
      
}
